今天要來介紹在 Blazor WebAssembly 與 JavaScript 的互動方式,也就是 JavaScript interop,畢竟目前有些行為如果不透過 JavaScript 是無法實現的,如在魔術技巧 - 取得元件參考提到的 Focus 元素等 DOM 的操作 ,與使用 windows 物件提供的成員。所以目前的 Blazor WebAssembly 還是需要借助撰寫 JavaScript 來達成特地行為。
要從 .NET 呼叫 JavaScript,只需要在元件注入 JSRuntime
即可如:
@inject IJSRuntime JSRuntime
並且透過 InvokeAsync
來呼叫指定的 JavaScript 函式,而其參數有:
identifier(string
):呼叫方法的識別碼,是相對於全域範圍(window
),也就是如果想要呼叫 window.someScope.someFunction
,則識別碼為 someScope.someFunction
。
args(Object[]
):呼叫方法的引數陣列,也就是如果呼叫的 JavaScript 方法需要兩個參數,就寫兩個引數,但要注意每個引數都必須是能夠 JSON 序列化。
cancellationToken(CancellationToken
):發出取消操作的信號,指定此參數將覆蓋所有預設的取消信號,例如因為超時(DefaultAsyncTimeout)而導致的取消。
timeout(TimeSpan
):超過指定時間則取消操作,指定此參數將覆蓋預設時間。
而傳回值為 ValueTask<TValue>
,TValue
應符合最適合對應至 JavaScript 所傳回 JSON 型別的 .NET 型別,且如果 JavaScript 傳回的是 Promise,則會拆開並傳回 Promise 所等待的結果。
倘若 JavaScript 是傳回 void(0)/void
,則可以使用 InvokeVoidAsync
來表示,其參數與上述相同。
而撰寫 JavaScript 時,建議是新增 .js
檔在 wwwroot
目錄下,並透過引用的方法加在 wwwroot/index.html
中如:
<!--wwwroot/index.html-->
<script src="exampleJsInterop.js"></script>
切勿將 <script>
標籤放在元件檔中,因為 <script>
無法動態變更。
在大部分情況下請不要透過 JavaScript 來修改 DOM,因為 JavaScript 可能會干擾 Blazor 的變更追蹤。
如果要反過來,使用 JavaScript 來呼叫 .NET 程式碼也是可行的,只需要建立帶有 [JSInvokable]
屬性的公開靜態方法即可如:
[JSInvokable]
public static int Sum(int a, int b) => a + b;
而 JavaScript 的呼叫方式為:
DotNet.invokeMethodAsync('{APP ASSEMBLY}', 'Sum', 1, 2)
.then(data => {
console.log(data);
});
其中的 {APP ASSEMBLY}
是應用程式的名稱,也就是說如果有兩個以上一樣名稱的公開靜態方法,就會因為不知道需要執行誰而導致程式錯誤。
要解決這個問題,我們可以將元件功能抽成一個服務,在傳送資料給 JavaScript 時,可以透過 DotNetObjectReference
將服務包在裡面,使得 JavaScript 呼叫 .NET 方法時,可以直接呼叫服務的方法,如:
// Day22SampleService.cs
public class Day22SampleService
{
[JSInvokable]
public int Sum(int a, int b) => a + b;
}
// Day22Sample.razor
@code {
private DotNetObjectReference<Day22SampleService> objRef;
private async Task<string> callDotNetAndPrintData2()
{
objRef = DotNetObjectReference.Create(new Day22SampleService());
return await JSRuntime.InvokeAsync<string>("exampleJsFunctions.callDotNetAndPrintData2", objRef);
}
}
// js
window.exampleJsFunctions = {
callDotNetAndPrintData2: function (dotnetHelper) {
return dotnetHelper.invokeMethodAsync('Sum', 1, 3)
.then(data => {
console.log(data);
});
}
};
這樣一來就可以準確鎖定特定服務給 JavaScript 呼叫。
以上就是 .NET 與 JavaScript 的互動方式,如果想看完整範例可以參考範本程式碼 - day22。
感謝大家的閱讀,我們明天見。
參考資料
從 .NET 呼叫 JavaScript
從 JavaScript 呼叫 .NET